home *** CD-ROM | disk | FTP | other *** search
Text File | 1989-12-08 | 6.9 KB | 258 lines | [TEXT/GEOL] |
- Item 3664185 8-Dec-89 10:28
-
- From: MADA2 MacApp Dev Assoc, Curtis Faith
-
- To: D1950 CSG, Don Phillips,PRT
-
- cc: MACAPP.TECH$ MacApp Technical
-
- Sub: RE: Failure Handling (long)
-
- Jo-Anne,
-
- Failure handling can be trickier than it looks. In you example a lot depends
- on exactly what you are creating the objects for. If you are later going to
- assign them to fields of TTObject4 then your handling can be simplified.
-
- The issues as I see them are this:
-
- 1) You can have 9 possible failures.
- a) during each of the 3 creations (NEW's).
- b) during each of the 3 TInitializations.
- c) during each of the 3 { Do something that can fails }
-
- 2) A failure in the first 2 areas for the first object needs no handler as the
- object will either never have been created in the case of FailNIL or it will be
- free automatically in the case of tmpObject1.IObject1.
-
- 3) A failure after where you insert the first handler needs to free the first
- object. This and the above apply to all 3 objects.
-
- 4) Since each object can have already been freed via the IObjectX method one
- need make allowances for non-NIL but already freed objects. THIS IS WHAT
- REALLY COMPLICATES MATTERS. For if an object could be guarranteed to be either
- valid and or NIL then you could have one handler:
-
- PROCEDURE HandleFailure( error : OSErr; message : LONGINT );
-
- BEGIN
- IF tmpObject1 <> NIL THEN
- FreeIfObject(tmpObject1);
- IF tmpObject2 <> NIL THEN
- FreeIfObject(tmpObject2);
- IF tmpObject3 <> NIL THEN
- FreeIfObject(tmpObject3);
- END;
-
- and even the NIL tests in the above would be unnecessary as FreeIfObject tests
- for this already (I like to put them in for clarities sake).
-
-
- 5) None of the NIL assignments that you have appear to be necessary. This is
- because there is no chance that any of the objects will be FreeIfObject'd until
- after they have been NEW'd, at which point they would either be set to NIL by
- NEW or be a valid reference.
-
- There is another way to handle the above situation that might be preferable but
- it is still a little messy. You could define 3 more local variables:
-
- PROCEDURE TTObject4.DoSomethingOtherThanInitialization;
-
- VAR
- aObject1: TObject1;
- aObject2: TObject2;
- aObject2: TObject2;
- tmpObject1 : TTObject1;
- tmpObject2 : TTObject2;
- tmpObject3 : TTObject3;
- fi : FailInfo;
-
- PROCEDURE HandleFailure( error : OSErr; message : LONGINT );
-
- BEGIN
- IF aObject1 <> NIL THEN
- FreeIfObject(aObject1);
- IF aObject2 <> NIL THEN
- FreeIfObject(aObject2);
- IF aObject3 <> NIL THEN
- FreeIfObject(aObject3);
- END;
-
- BEGIN
- aObject1 := NIL;
- aObject2 := NIL;
- aObject3 := NIL;
-
- CatchFailures( fi, HandleFailure );
-
- New( tmpObject1 );
- FailNIL( tmpObject1 );
- tmpObject1.IObject1;
- aObject1 := tmpObject1;
-
- { Do something that could fail 1. }
-
- New( tmpObject2 );
- FailNIL( tmpObject2 );
- tmpObject2.IObject2;
- aObject2 := tmpObject2;
-
- { Do something that could fail 2. }
-
- New( tmpObject3 );
- FailNIL( tmpObject3 );
- tmpObject3.IObject3;
- aObject3 := tmpObject3;
-
- { Do something that could fail 3. }
-
- Success( fi );
-
- END;
-
- Here we correctly handle a failure in any of the above 9 places and still have
- only one failure handler. A Failure anywhere after an assignment aObjectX :=
- tmpObjectX will free aObjectX.
-
- I believe that there would be less overhead involved in the storage of the 3
- new variables and their assignment than in using the 2 additional failure
- handlers that you listed.
-
- A closely related example would be where one would want to assign each of the 3
- objects to a field of TObject4 and TObject4.Free freed each field if non-NIL.
-
- PROCEDURE TTObject4.Free; OVERRIDE;
- BEGIN
- IF aObject1 <> NIL THEN
- FreeIfObject(aObject1);
- IF aObject2 <> NIL THEN
- FreeIfObject(aObject2);
- IF aObject3 <> NIL THEN
- FreeIfObject(aObject3);
-
- INHERITED Free;
- END;
-
- PROCEDURE TTObject4.DoSomethingOtherThanInitialization;
-
- VAR
- tmpObject1 : TTObject1;
- tmpObject2 : TTObject2;
- tmpObject3 : TTObject3;
- fi : FailInfo;
-
- PROCEDURE HandleFailure( error : OSErr; message : LONGINT );
-
- BEGIN
- Free;
- END;
-
- BEGIN
- aObject1 := NIL;
- aObject2 := NIL;
- aObject3 := NIL;
-
- CatchFailures( fi, HandleFailure );
-
- New( tmpObject1 );
- FailNIL( tmpObject1 );
- tmpObject1.IObject1;
- fObject1 := tmpObject1;
-
- { Do something that could fail 1. }
-
- New( tmpObject2 );
- FailNIL( tmpObject2 );
- tmpObject2.IObject2;
- fObject2 := tmpObject2;
-
- { Do something that could fail 2. }
-
- New( tmpObject3 );
- FailNIL( tmpObject3 );
- tmpObject3.IObject3;
- fObject3 := tmpObject3;
-
- { Do something that could fail 3. }
-
- Success( fi );
-
- END;
-
- One further variation that would complicate matters would be in the above case
- if each of the 3 objects did not free itself when failing in IOBjectX.
-
- PROCEDURE TTObject4.DoSomethingOtherThanInitialization;
-
- VAR
- tmpObject1 : TTObject1;
- tmpObject2 : TTObject2;
- tmpObject3 : TTObject3;
- fi : FailInfo;
-
- PROCEDURE HandleFailure( error : OSErr; message : LONGINT );
-
- BEGIN
- Free;
- END;
-
- BEGIN
- aObject1 := NIL;
- aObject2 := NIL;
- aObject3 := NIL;
-
- CatchFailures( fi, HandleFailure );
-
- New( tmpObject1 );
- FailNIL( tmpObject1 );
- fObject1 := tmpObject1;
- tmpObject1.IObject1;
-
- { Do something that could fail 1. }
-
- New( tmpObject2 );
- FailNIL( tmpObject2 );
- fObject2 := tmpObject2;
- tmpObject2.IObject2;
-
- { Do something that could fail 2. }
-
- New( tmpObject3 );
- FailNIL( tmpObject3 );
- fObject3 := tmpObject3;
- tmpObject3.IObject3;
-
- { Do something that could fail 3. }
-
- Success( fi );
-
- END;
-
- In this case merely moving the assignment of fObjectX := tmpObjectX up before
- the initialization will accomplish our goal, since after this assignment is
- made we can be sure that the newly created object will get Free'd when
- TObject4.Free is called from the "HandleFailure" failure handler.
-
- In general one needs to examine things very closely when implementing these
- confusing failure handlers. In particular it is important what the effects of
- a failure during the Initialization stage of an object are. If an object will
- free itself one need make allowances for non-NIL but already freed objects.
-
- In my opinion, additional temporary variables or fields that have been preset
- to NIL and are assigned just after the initialization method are preferable to
- having multiple failure handlers.
-
- All this leads one to believe that automatic garbage collection would indeed be
- a valuable thing. In that case failure handlers would be far less frequently
- necessary.
-
- I hope I did not add to the confusion.
-
- - Curtis
-
-
-
-
-
-
-